/**
 * SPDX-FileCopyrightText: 2023-2025 Sangfor Technologies Inc.
 * SPDX-License-Identifier: Mulan PSL v2
 */
/**
 * Created by ued on 2016/11/9.
 */

import { isObject } from 'src/util/typeof';

/**
 * Copies all the properties of config to obj.
 * @param {Object} obj The receiver of the properties
 * @param {Object} config The source of the properties
 * @return {Object} returns obj
 */
type ApplyTwo<T extends AnyObject, U extends AnyObject> = {[K in Extract<keyof T, keyof U>]: U[K]} & 
        {[K in Exclude<keyof T, keyof U>]: T[K]} & 
        {[K in Exclude<keyof U, keyof T>]: U[K]}
interface Apply {
    <T extends AnyObject>(a: T): T
    <T extends AnyObject, U extends AnyObject>(a: T, b: U): ApplyTwo<T, U>
    <T extends AnyObject, U extends AnyObject, K extends AnyObject>(a: T, b: U, c: K): ApplyTwo<ApplyTwo<T, U>, K>
    (obj: AnyObject, ...rest: AnyObject[]): SafeAny
}
export let apply:Apply = function (...objs: AnyObject[]) {
    let obj = objs[0];
    let config = objs.slice(1);
    config.forEach((config) => {
        if (obj && config && typeof config === 'object') {
            for (let p in config) {
                if (config.hasOwnProperty(p)) {
                    obj[p] = config[p];
                }
            }
        }
    });

    return obj;
};

type ApplyType<T extends AnyObject, U extends AnyObject> = T & {
    [K in Exclude<keyof U, keyof T>]: U[K]
}

interface ApplyIf {
    <T extends AnyObject> (a: T): T
    <T extends AnyObject, U extends AnyObject>(a: T, b: U): ApplyType<T, U>
    <T extends AnyObject, U extends AnyObject, K extends AnyObject>(a: T, b: U, c: K): ApplyType<ApplyType<T, U>, K>
    (obj: AnyObject, ...rest: AnyObject[]): SafeAny
}

export let applyIf: ApplyIf = function (...objs: AnyObject[]) {
    let obj = objs[0];
    let config = objs.slice(1);
    if (obj) {
        config.forEach((config) => {
            for (let p in config) {
                if (config.hasOwnProperty(p) && typeof obj[p] === 'undefined') {
                    obj[p] = config[p];
                }
            }
        });
    }
    return obj;
};

/**
 * 原对象的属性值覆盖，但并不继承扩展的属性
 * @param {Object} obj The receiver of the properties
 * @param {Object} config The source of the properties
 * @return {Object} returns obj
 */
type ApplyCoverTwo <T extends AnyObject, U extends AnyObject>  = {
    [K in Extract<keyof T, keyof U>]: U[K]
} & {
    [K in Exclude<keyof T, keyof U>]: T[K]
}
interface ApplyCover {
    <T extends AnyObject>(a: T): T
    <T extends AnyObject, U extends AnyObject>(a: T, b: U): ApplyCoverTwo<T, U>
    <T extends AnyObject, U extends AnyObject, K extends AnyObject>(a: T, b: U, c: K): ApplyCoverTwo<ApplyCoverTwo<T, U>, K>
    (obj: AnyObject, ...rest: AnyObject[]): SafeAny
}
export let applyCover: ApplyCover = function (...objs: AnyObject[]) {
    let obj = objs[0];
    let config = objs.slice(1);
    if (obj) {
        config.forEach(config => {
            for (let p in config) {
                if (config.hasOwnProperty(p) && obj.hasOwnProperty(p)) {
                    obj[p] = config[p];
                }
            }
        });
    }
    return obj;
};

export let applyCoverAssign: ApplyCover = function (...objs: AnyObject[]) {
    let obj = objs[0];
    let config = objs.slice(1);
    if (obj) {
        config.forEach(config => {
            for (let p in config) {
                if (config.hasOwnProperty(p) && obj.hasOwnProperty(p)) {
                    if (isObject(config[p])) {
                        Object.assign(obj[p], config[p]);
                    } else {
                        obj[p] = config[p];
                    }
                }
            }
        });
    }
    return obj;
};
